#include "sshmonitor.h"
#include <QDebug>
#include <QTextStream>
#include <QStringList>
#include <QtMath>
#include <QDateTime>
#include <QDir>
#include <QFile>

SSHMonitor::SSHMonitor(QObject *parent)
    : QObject(parent)
    , m_connected(false)
    , m_updateTimer(new QTimer(this))
    , m_sshProcess(new QProcess(this))
    , m_firstRead(true)
    , m_lastUser(0)
    , m_lastSystem(0)
    , m_lastIdle(0)
    , m_lastTotal(0)
{
    // 连接SSH进程信号
    connect(m_sshProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            this, &SSHMonitor::onSSHCommandFinished);
    connect(m_sshProcess, QOverload<QProcess::ProcessError>::of(&QProcess::errorOccurred),
            this, &SSHMonitor::onSSHCommandError);
    // 连接定时器信号
    connect(m_updateTimer, &QTimer::timeout, this, &SSHMonitor::updateRemoteData);
    qDebug() << "SSH监控器初始化完成";
}

SSHMonitor::~SSHMonitor() {
    // 断开连接
    disconnect();
}

// 建立SSH 连接，测试连接是否成功，启动定时器更新数据
bool SSHMonitor::connectToHost(const QString &host, const QString &user) {
    // 如果建立了连接断开连接
    if(m_connected) {
        disconnect();
    }
    m_host = host;
    m_user = user;
    qDebug() << "尝试SSH连接到：" << user << "@" << host;

    // 先设置连接状态为true，允许executeSSHCommand执行
    m_connected = true;

    //测试SSH连接
    QString testResult = executeSSHCommand("echo 'SSH connection test'");
    qDebug() << "测试结果:" << testResult;
    if(testResult.contains("SSH connection test")) {
        //连接上了
        //开启定时器 每2s更新一次数据
        m_updateTimer->start(2000);
        // 发射连接状态变化信号
        emit connectionStatusChanged(true);
        qDebug() << "SSH连接成功";
        return true;
    }else {
        // 连接失败，重置状态
        m_connected = false;
        emit errorOccurred("SSH连接失败");
        qDebug() << "SSH连接失败";
        return false;
    }
}

// 断开SSH连接
void SSHMonitor::disconnect() {
    if(m_connected) {
        m_updateTimer->stop();
        m_connected = false;
        emit connectionStatusChanged(false);
        qDebug() << "SSH连接已断开";
    }
}

// 是否连接
bool SSHMonitor::isConnected() const {
    return m_connected;
}

// 得到远程CPU数据
CPUData SSHMonitor::getRemoteCPUData() const {
    return m_currentData;
}

// 执行SSH命令
QString SSHMonitor::executeSSHCommand(const QString &command){
    // 如果没有建立连接返回空字符串
    if(!m_connected){
        qDebug() << "SSH未连接，无法执行命令";
        return QString();
    }

    QStringList arguments;

    // 添加SSH选项以确保正确连接
    arguments << "-o" << "StrictHostKeyChecking=no";  // 跳过主机密钥检查
    arguments << "-o" << "UserKnownHostsFile=/dev/null";  // 不保存主机密钥
    arguments << "-o" << "ConnectTimeout=10";  // 连接超时10秒
    arguments << "-o" << "BatchMode=yes";  // 批处理模式，不交互
    arguments << QString("%1@%2").arg(m_user).arg(m_host) << command;

    qDebug() << "执行SSH命令:" << "ssh" << arguments;

    m_sshProcess->start("ssh", arguments);
    m_sshProcess->waitForFinished(10000);    //等待10秒

    qDebug() << "SSH进程退出码:" << m_sshProcess->exitCode();

    // 先保存输出，避免多次调用readAllStandardOutput
    QString stdOutput = QString::fromUtf8(m_sshProcess->readAllStandardOutput());
    QString stdError = QString::fromUtf8(m_sshProcess->readAllStandardError());

    qDebug() << "SSH标准输出:" << stdOutput;
    qDebug() << "SSH错误输出:" << stdError;

    if(m_sshProcess->exitCode() == 0) {
        return stdOutput;
    }else {
        qDebug() << "SSH命令执行失败:" << stdError;
        return QString();
    }
}

void SSHMonitor::updateRemoteData() {
    if(!m_connected) {
        return;
    }

    QString data = executeSSHCommand("cat /proc/stat | head -1");
    if(!data.isEmpty()) {
        calculateCPUUsage(data);
    }
}

void SSHMonitor::calculateCPUUsage(const QString &data) {
    // 解析 /proc/stat 第一行数据
    // 格式：cpu user nice system idle iowait irq softirq steal guest guest_nice
    QStringList parts = data.split(" ", Qt::SkipEmptyParts);
    if(parts.size() < 5) {
        return;
    }

    //跳过cpu 标识符
    unsigned long long user = parts[1].toULongLong();
    unsigned long long nice = parts[2].toULongLong();
    unsigned long long system = parts[3].toULongLong();
    unsigned long long idle = parts[4].toULongLong();

    // 第一次不能计算使用率，直接返回
    if(m_firstRead) {
        m_lastUser = user;
        m_lastSystem = system;
        m_lastIdle = idle;
        m_lastTotal = user + system + idle + nice;
        m_firstRead = false;
        return;
    }

    // 不是第一次，计算差值
    unsigned long long deltaUser = user - m_lastUser;
    unsigned long long deltaSystem = system - m_lastSystem;
    unsigned long long deltaIdle = idle - m_lastIdle;
    unsigned long long deltaTotal = (user + nice + system + idle) - m_lastTotal;

    // 计算使用率
    if(deltaTotal > 0) {
        double usrPercent = (deltaUser*100.0)/deltaTotal;
        double SystemPercent = (deltaSystem*100.0)/deltaTotal;
        double IdlePercent = (deltaIdle *100.0) / deltaTotal;
        double totalPercent = 100 - IdlePercent;

        // 限制在0 - 100 之内
        m_currentData.user = qBound(0.0, usrPercent, 100.0);
        m_currentData.system = qBound(0.0, SystemPercent, 100.0);
        m_currentData.idle = qBound(0.0, IdlePercent, 100.0);
        m_currentData.total = qBound(0.0, totalPercent, 100.0);

        // 使用相对时间戳，避免与本地数据时间轴冲突
        // 从连接开始计算相对时间，确保图表能正确显示
        static qint64 startTime = QDateTime::currentMSecsSinceEpoch();
        m_currentData.timestamp = QDateTime::currentMSecsSinceEpoch() - startTime + 1000; // 从1秒开始

        emit dataUpdated(m_currentData);
        qDebug() << "远程CPU数据:" << m_currentData.total << "%";
    }

    // 更新上次数据
    m_lastUser = user;
    m_lastSystem = system;
    m_lastIdle = idle;
    m_lastTotal = user + nice + system + idle;
}

//
void SSHMonitor::onSSHCommandFinished(int exitCode, QProcess::ExitStatus exitStatus){
    if(exitCode != 0){
        emit errorOccurred(QString("SSH命令执行失败，退出码：%1").arg(exitCode));
    }
}

void SSHMonitor::onSSHCommandError(QProcess::ProcessError error) {
    QString errorMsg;
    switch(error){
    case QProcess::FailedToStart:
        errorMsg = "SSH命令启动失败";
        break;
    case QProcess::Crashed:
        errorMsg = "SSH命令崩溃";
        break;
    case QProcess::Timedout:
        errorMsg = "SSH命令超时";
        break;
    default:
        errorMsg = "SSH命令执行错误";
        break;
    }
    emit errorOccurred(errorMsg);
}
